/*
MIT License 

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов, 

https://bmstu.codes/lsx/simodo
*/

#ifndef simodo_token_Token
#define simodo_token_Token

/*! \file Token.h
    \brief Токен входного алфавита
*/

#include "simodo/inout/token/Lexeme.h"
#include "simodo/inout/token/TokenLocation.h"
#include "simodo/inout/token/TokenQualification.h"


namespace simodo::inout
{
    /*!
     * \brief Токен лексического разбора
     *
     * Основной элемент, генерируемый сканером (см. class Scanner). Содержит параметры положения в тексте
     * и другие характеристики токена (в отличие от лексемы, которая содержит строку содержимого и тип).
     * 
     * Значение токена, в отличие от лексемы, хранится как есть вместе со служебными элементами
     * (например, для аннотации хранятся обрамляющие кавычки и внутренние служебные символы кавычек).
     * 
     * Токен не может быть создан без указания локации, поскольку это основное свойство токена. 
     * Если локация неизвестна, пользуйтесь константой нулевой локации null_token_location.
     *
     * \attention Значение строки токена может отличаться от строки лексемы! Принципиальное отличие сводится к тому,
     * что строка токена содержит лексический символ в том виде, в котором он присутствует в исходном файле.
     * В то время, как строка лексемы содержит обработанный лексический символ, подготовленный для работы с
     * синтаксическим анализатором и генератором кода. Например, строка токена содержит строковую константу вместе с
     * кавычками, а строка лексемы - без.
     */
     
    class Token: public Lexeme
    {
        std::u16string      _token;                  ///< Строка токена
        TokenLocation       _location;               ///< Позиция токена в исходном тексте
        TokenQualification  _qualification = TokenQualification::None;   ///< Уточняющий квалификатор токена
        context_index_t     _context = NO_TOKEN_CONTEXT_INDEX;     ///< Индекс параметра с пометками начала и конца

    public:
        Token() = delete;
        Token(Lexeme lexeme, std::u16string token, TokenLocation location, 
              TokenQualification qualification = TokenQualification::None,
              context_index_t lexical_markups_index = NO_TOKEN_CONTEXT_INDEX) 
            : Lexeme(lexeme)
            , _token(token)
            , _location(location)
            , _qualification(qualification)
            , _context(lexical_markups_index)
        {}
        Token(Lexeme lexeme, TokenLocation location) 
            : Lexeme(lexeme)
            , _token({})
            , _location(location)
            , _qualification(TokenQualification::None)
            , _context(NO_TOKEN_CONTEXT_INDEX)
        {}
        Token(LexemeType type, std::u16string lexeme, TokenLocation location, 
              TokenQualification qualification = TokenQualification::None,
              context_index_t lexical_markups_index = NO_TOKEN_CONTEXT_INDEX) 
            : Lexeme(lexeme, type)
            , _token(u"")
            , _location(location)
            , _qualification(qualification)
            , _context(lexical_markups_index)
        {}

        const std::u16string & token() const { return _token.empty() ? lexeme() : _token; }
        TokenLocation          location() const { return _location; }
        TokenQualification     qualification() const { return _qualification; }
        context_index_t        context() const { return _context; }

        Location               makeLocation(const uri_set_t & uri_set) const 
        {
            return _location.makeLocation(uri_set);
        }
    };

    inline const static Token null_token {{},{},null_token_location};

}

#endif // simodo_token_Token
